package com.ds.infra.rpc.core.transport.server.handler;

import com.ds.infra.rpc.core.cache.ServiceCache;
import com.ds.infra.rpc.core.protocol.RpcProtocol;
import com.ds.infra.rpc.core.protocol.RpcRequest;
import com.ds.infra.rpc.core.protocol.RpcResponse;
import com.ds.infra.rpc.core.util.ReflectionUtils;
import com.ds.infra.rpc.registry.util.ServiceKeyUtils;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;

/**
 * 业务请求处理器（线程安全）
 *
 * @author WeiShaoying
 */
@Slf4j
@ChannelHandler.Sharable
public class RpcRequestHandler extends SimpleChannelInboundHandler<RpcProtocol<RpcRequest>> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcProtocol<RpcRequest> protocol) {
        RpcResponse response = new RpcResponse();
        log.info("====收到请求: {}", protocol.getBody());
        response.setRequestId(protocol.getBody().getRequestId());

        try {
            Object result = invokeService(protocol.getBody());
            log.info("====调用结果: {}", result);
            response.setData(result);
        } catch (Exception e) {
            response.setErrorMsg(e.getMessage());
        }

        // 修正协议包构建方式
        RpcProtocol<RpcResponse> responseProtocol = new RpcProtocol<>(
                new RpcProtocol.Header(
                        RpcProtocol.MsgType.RESPONSE.getValue(),
                        0 // 长度占位
                ),
                response
        );
        ctx.writeAndFlush(responseProtocol);
    }

    private Object invokeService(RpcRequest request) throws Exception {
        String serviceKey = ServiceKeyUtils.buildServiceKey(
                request.getClassName(),
                request.getVersion()
        );
        log.info("====服务键: {}", serviceKey);
        Object service = ServiceCache.getService(serviceKey);
        Method method = ReflectionUtils.findMethod(
                service.getClass(),
                request.getMethodName(),
                request.getParameterTypes()
        );
        log.info("====准备调用方法: {}", method);
        return ReflectionUtils.invokeMethod(service, method, request.getParameters());
    }
}
